package com.thghh.chinesewordsegmentation;

import com.hankcs.hanlp.HanLP;
import com.hankcs.hanlp.seg.CRF.CRFSegment;
import com.hankcs.hanlp.seg.Dijkstra.DijkstraSegment;
import com.hankcs.hanlp.seg.NShort.NShortSegment;
import com.hankcs.hanlp.seg.Segment;
import com.hankcs.hanlp.seg.common.Term;
import com.hankcs.hanlp.tokenizer.IndexTokenizer;
import com.hankcs.hanlp.tokenizer.NLPTokenizer;
import com.hankcs.hanlp.tokenizer.SpeedTokenizer;
import com.hankcs.hanlp.tokenizer.StandardTokenizer;
import java.util.List;
/**
 * Created by 充电了么App - 陈敬雷
 * 充电了么App官网：http://chongdianleme.com/
 * 充电了么App - 专注上班族职业技能提升充电学习的在线教育平台
 * HanLP中文分词功能演示，开源地址：https://github.com/hankcs/HanLP
*/
public class HanLPDemo {
    public static void main(String[] args) {
        segment();//常用默认分词：HanLP.segment
        standardSegment();//标准分词：StandardTokenizer.segment
        NLPSegment();// NLP分词
        indexTokenizerSegment();//索引分词
        nShortSegment();//N-最短路径分词
        CRFSegment();//CRF分词
        highSpeedSegment();//极速词典分词
    }
    /**
     *1.常用默认分词：HanLP.segment
     * HanLP对词典的数据结构进行了长期的优化，可以应对绝大多数场景。哪怕HanLP的词典上百兆也无需担心，因为在内存中被精心压缩过。
     * 如果内存非常有限，请使用小词典。HanLP默认使用大词典，同时提供小词典。全部词典和模型都是惰性加载的，不使用的模型相当于不存在，可以自由删除。
     * HanLP.segment其实是对StandardTokenizer.segment标准分词的包装，和标准分词的结果是一样的。
     */
    public static void segment() {
        String s = "分布式机器学习实战（人工智能科学与技术丛书）深入浅出，逐步讲解分布式机器学习的框架及应用配套个性化推荐算法系统、人脸识别、对话机器人等实战项目。";
        List<Term> termList =HanLP.segment(s);
        System.out.println(termList);
        //输出结果如下：分词结果包含词性，比如分布式的词性b代表区别词，机器学习的词性gi代表计算机相关词汇，实战的词性n代表名称，
        // 后面每个词都返回了对应的词性，这里不一一举例，下章我们会单独讲词性标注，列出所有的词性表。
        //[分布式/b, 机器学习/gi, 实战/n, （/w, 人工智能/n, 科学/n, 与/p, 技术/n, 丛书/n, ）/w, 深入浅出/i, ，/w, 逐步/d, 讲解/v, 分布式/b, 机器学习/gi, 的/uj, 框架/n, 及/c, 应用/vn, 配套/a, 个性化/v, 推荐/v, 算法/n, 系统/n, 、/w, 人脸/n, 识别/v, 、/w, 对话/vn, 机器人/n, 等/u, 实战/n, 项目/n, 。/w]
    }

    /**
     *2.标准分词：StandardTokenizer.segment
     * HanLP中有一系列“开箱即用”的静态分词器，以Tokenizer结尾，在接下来的例子中会继续介绍。
     * HanLP.segment其实是对StandardTokenizer.segment的包装。
     * 分词结果包含词性，每个词性的意思下章详细讲解。
     */
    public static void standardSegment() {
        String s = "分布式机器学习实战（人工智能科学与技术丛书）深入浅出，逐步讲解分布式机器学习的框架及应用配套个性化推荐算法系统、人脸识别、对话机器人等实战项目。";
        List<Term> termList = StandardTokenizer.segment(s);
        System.out.println(termList);
        termList = HanLP.segment(s);
        //输出结果如下：可以看到和上面的HanLP.segment结果是一样的。
        //[分布式/b, 机器学习/gi, 实战/n, （/w, 人工智能/n, 科学/n, 与/p, 技术/n, 丛书/n, ）/w, 深入浅出/i, ，/w, 逐步/d, 讲解/v, 分布式/b, 机器学习/gi, 的/uj, 框架/n, 及/c, 应用/vn, 配套/a, 个性化/v, 推荐/v, 算法/n, 系统/n, 、/w, 人脸/n, 识别/v, 、/w, 对话/vn, 机器人/n, 等/u, 实战/n, 项目/n, 。/w]
    }
    /**
     *3.NLP分词：NLPTokenizer.segment
     NLP分词NLPTokenizer会执行词性标注和命名实体识别，由结构化感知机序列标注框架支撑。默认模型训练自9970万字的大型综合语料库，是已知范围内全世界最大的中文分词语料库。
     语料库规模决定实际效果，面向生产环境的语料库应当在千万字量级。用户可以在自己的语料上训练新模型以适应新领域、识别新的命名实体。
     */
    public static void NLPSegment() {
        String s = "分布式机器学习实战（人工智能科学与技术丛书）深入浅出，逐步讲解分布式机器学习的框架及应用配套个性化推荐算法系统、人脸识别、对话机器人等实战项目。";
        System.out.println(NLPTokenizer.segment(s));
        //输出结果如下：
        //[分布式/b, 机器学习/gi, 实战/n, （/w, 人工智能/n, 科学/n, 与/p, 技术/n, 丛书/n, ）/w, 深入浅出/i, ，/w, 逐步/d, 讲解/v, 分布式/b, 机器学习/gi, 的/uj, 框架/n, 及/c, 应用/vn, 配套/a, 个性化/v, 推荐/v, 算法/n, 系统/n, 、/w, 人脸/n, 识别/v, 、/w, 对话/vn, 机器人/n, 等/u, 实战/n, 项目/n, 。/w]
    }
    /**
     *4.索引分词：IndexTokenizer.segment
     索引分词IndexTokenizer是面向搜索引擎的分词器，能够对长词全切分，另外通过term.offset可以获取单词在文本中的偏移量。
     任何分词器都可以通过基类Segment的enableIndexMode方法激活索引模式。
     */
    public static void indexTokenizerSegment() {
        String s = "分布式机器学习实战（人工智能科学与技术丛书）深入浅出，逐步讲解分布式机器学习的框架及应用配套个性化推荐算法系统、人脸识别、对话机器人等实战项目。";
        List<Term> termList = IndexTokenizer.segment(s);
        for (Term term : termList)
        {
            System.out.println(term + " [" + term.offset + ":" + (term.offset + term.word.length()) + "]");
        }
        //输出结果如下：
        /**
         分布式/b [0:3]
         分布/v [0:2]
         机器学习/gi [3:7]
         机器/n [3:5]
         学习/v [5:7]
         实战/n [7:9]
         （/w [9:10]
         人工智能/n [10:14]
         人工/n [10:12]
         智能/n [12:14]
         科学/n [14:16]
         与/p [16:17]
         技术/n [17:19]
         丛书/n [19:21]
         ）/w [21:22]
         深入浅出/i [22:26]
         深入/v [22:24]
         ，/w [26:27]
         逐步/d [27:29]
         讲解/v [29:31]
         分布式/b [31:34]
         分布/v [31:33]
         机器学习/gi [34:38]
         机器/n [34:36]
         学习/v [36:38]
         的/uj [38:39]
         框架/n [39:41]
         及/c [41:42]
         应用/vn [42:44]
         配套/a [44:46]
         个性化/v [46:49]
         个性/n [46:48]
         推荐/v [49:51]
         算法/n [51:53]
         系统/n [53:55]
         、/w [55:56]
         人脸/n [56:58]
         识别/v [58:60]
         、/w [60:61]
         对话/vn [61:63]
         机器人/n [63:66]
         机器/n [63:65]
         等/u [66:67]
         实战/n [67:69]
         项目/n [69:71]
         。/w [71:72]
         */
    }
    /**
     * 5.N-最短路径分词:nShortSegment.seg
     N最短路分词器NShortSegment比最短路分词器慢，但是效果稍微好一些，对命名实体识别能力更强。
     一般场景下最短路分词的精度已经足够，而且速度比N最短路分词器快几倍，请酌情选择。
     */
    public static void nShortSegment() {
        String s = "分布式机器学习实战（人工智能科学与技术丛书）深入浅出，逐步讲解分布式机器学习的框架及应用配套个性化推荐算法系统、人脸识别、对话机器人等实战项目。";
        Segment nShortSegment = new NShortSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);
        Segment shortestSegment = new DijkstraSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);
        System.out.println("N-最短分词：" + nShortSegment.seg(s) + "\n最短路分词：" + shortestSegment.seg(s));
        //输出结果如下：
        //N-最短分词：[分布式/b, 机器/n, 学习/v, 实战/n, （/w, 人工智能/n, 科学/n, 与/p, 技术/n, 丛书/n, ）/w, 深入浅出/i, ，/w, 逐步/d, 讲解/v, 分布式/b, 机器/n, 学习/v, 的/uj, 框架/n, 及/c, 应用/vn, 配套/a, 个性化/v, 推荐/v, 算法/n, 系统/n, 、/w, 人脸/n, 识别/v, 、/w, 对话/vn, 机器人/n, 等/u, 实战/n, 项目/n, 。/w]
        //最短路分词：[分布式/b, 机器/n, 学习/v, 实战/n, （/w, 人工智能/n, 科学/n, 与/p, 技术/n, 丛书/n, ）/w, 深入浅出/i, ，/w, 逐步/d, 讲解/v, 分布式/b, 机器/n, 学习/v, 的/uj, 框架/n, 及/c, 应用/vn, 配套/a, 个性化/v, 推荐/v, 算法/n, 系统/n, 、/w, 人脸/n, 识别/v, 、/w, 对话/vn, 机器人/n, 等/u, 实战/n, 项目/n, 。/w]
    }
    /**
     *6.CRF分词：CRFSegment
     CRF对新词有很好的识别能力，但是开销较大。
     */
    public static void  CRFSegment() {
        String s = "分布式机器学习实战（人工智能科学与技术丛书）深入浅出，逐步讲解分布式机器学习的框架及应用配套个性化推荐算法系统、人脸识别、对话机器人等实战项目。";
        Segment crfSegment = new CRFSegment();
        System.out.println(crfSegment.seg(s));
    }
    /**
     *7.极速词典分词：SpeedTokenizer.segment
     极速分词是词典最长分词，速度极其快，精度一般。在i7-6700K上跑出了4500万字每秒的速度。
     */
    public static void  highSpeedSegment() {
        String s = "分布式机器学习实战（人工智能科学与技术丛书）深入浅出，逐步讲解分布式机器学习的框架及应用配套个性化推荐算法系统、人脸识别、对话机器人等实战项目。";
        System.out.println(SpeedTokenizer.segment(s));
        long start = System.currentTimeMillis();
        int pressure = 100;
        for (int i = 0; i < pressure; ++i)
        {
            SpeedTokenizer.segment(s);
        }
        double costTime = (System.currentTimeMillis() - start) / (double)1000;
        System.out.printf("分词速度：%.2f字每秒", s.length() * pressure / costTime);
    }
}